package cn.fraudmetrix.octopus.modules.jacoco.service;

import cn.fraudmetrix.octopus.modules.jacoco.dao.JacocoCoverageDao;
import cn.fraudmetrix.octopus.modules.jacoco.entity.JacocoCoverageEntity;
import org.apache.commons.lang.StringUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import java.io.File;
import java.io.IOException;
import java.text.DecimalFormat;

/**
 * @author libao.zheng
 * @email libao.zheng@tongdun.net
 * @date 2019/1/17 17:29
 */
public class JacocoCoverageService {
    public static void calculate(Integer appId, String appName, boolean incremental, File coverageFile, JacocoCoverageDao jacocoCoverageDao) throws IOException {
        JacocoCoverageEntity jacocoCoverageEntity = new JacocoCoverageEntity();
        Document doc = Jsoup.parse(coverageFile, "UTF-8");
        Element tfoot = doc.getElementsByTag("tfoot").get(0);
        Element tbody = doc.getElementsByTag("tbody").get(0);
        if (StringUtils.isNotBlank(tbody.text())) {
            Elements tds = tfoot.getElementsByTag("td");
            String[] instructionText = tds.get(1).text().trim().split("of");
            double missedInstruction = Double.parseDouble(removeComma(instructionText[0]));
            double totalInstruction = Double.parseDouble(removeComma(instructionText[1]));
            String instructionCoverage = format((totalInstruction - missedInstruction) / totalInstruction);
            jacocoCoverageEntity.setInstructionCoverage(instructionCoverage);

            String[] branchText = tds.get(3).text().trim().split("of");
            double missedBranch = Double.parseDouble(removeComma(branchText[0]));
            double totalBranch = Double.parseDouble(removeComma(branchText[1]));
            String branchCoverage = format((totalBranch - missedBranch) / totalBranch);
            jacocoCoverageEntity.setBranchCoverage(branchCoverage);

            double missedCxty = Double.parseDouble(removeComma(tds.get(5).text()));
            double totalCxty = Double.parseDouble(removeComma(tds.get(6).text()));
            String cxtyCoverage = format((totalCxty - missedCxty) / totalCxty);
            jacocoCoverageEntity.setCxtyCoverage(cxtyCoverage);

            double missedLine = Double.parseDouble(removeComma(tds.get(7).text()));
            double totalLine = Double.parseDouble(removeComma(tds.get(8).text()));
            String lineCoverage = format((totalLine - missedLine) / totalLine);
            jacocoCoverageEntity.setLineCoverage(lineCoverage);

            double missedMethod = Double.parseDouble(removeComma(tds.get(9).text()));
            double totalMethod = Double.parseDouble(removeComma(tds.get(10).text()));
            String methodCoverage = format((totalMethod - missedMethod) / totalMethod);
            jacocoCoverageEntity.setMethodCoverage(methodCoverage);

            double missedClass = Double.parseDouble(removeComma(tds.get(11).text()));
            double totalClass = Double.parseDouble(removeComma(tds.get(12).text()));
            String classCoverage = format((totalClass - missedClass) / totalClass);
            jacocoCoverageEntity.setClassCoverage(classCoverage);
            String coverageType;
            if (incremental) {
                coverageType = "incremental";
            } else {
                coverageType = "full";
            }
            JacocoCoverageEntity result = jacocoCoverageDao.query(new JacocoCoverageEntity(appId, coverageType)).get(0);
            jacocoCoverageEntity.setAppId(appId);
            jacocoCoverageEntity.setAppName(appName);
            jacocoCoverageEntity.setCoverageType(coverageType);
            if (result == null) {
                jacocoCoverageDao.add(jacocoCoverageEntity);
            } else {
                jacocoCoverageDao.update(jacocoCoverageEntity);
            }
        }

    }

    private static String format(double number) {
        DecimalFormat df = new DecimalFormat("0.00%");
        return df.format(number);
    }

    private static String removeComma(String str) {
        return str.replace(",", "");
    }
}
